package online.zhangwenzhe.common.identity;

import online.zhangwenzhe.common.CustomProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.LocalDateTime;
import java.util.Random;

/**
 * Description
 * 类似雪花算法，比雪花算法可读性强，适合做订单号等
 *
 * 190306152132733001这个样子的号码
 *    12位     3位   3位
 * 年月日时分秒-机器码-序号
 * 190306145829-180-001
 *
 * Component注解只是为了实现从配置文件获取参数
 *
 * @author zhangwenzhe
 * @since 2018/8/15 下午3:23
 */
@Component
public class NewID {
    long machineLeft = 1000;
    long secondLeft = machineLeft * 1000;
    long minuteLeft = secondLeft * 100;
    long hourLeft = minuteLeft * 100;
    long dayLeft = hourLeft * 100;
    long monthLeft = dayLeft * 100;
    long yearLeft = monthLeft * 100;

    /**
     * 机器标识
     */
    private long machineId = 0;

    private long sequence = 0;
    private int lastSecond = 0;
    private volatile static NewID singleton;

    @Autowired
    private CustomProperties customProperties;

    /**
     * SpringBoot程序启动方式导致要这么读取配置文件
     */
    @PostConstruct
    public void initBySpringBoot() {
        if (customProperties != null &&
                customProperties.getApplication() != null) {
            this.machineId = customProperties.getApplication().getMachineId();
        }

        initMachineId();

        singleton = this;
    }

    private void initMachineId(){
        if (machineId == 0) {
            Random random = new Random();
            machineId = random.nextInt(1000);
        }
    }

    private NewID(){
        initMachineId();
    }

    private static NewID getInstance() {
        if (singleton == null) {
            synchronized (NewID.class) {
                if (singleton == null) {
                    singleton = new NewID();
                }
            }
        }
        return singleton;
    }

    public static long next() {
        return getInstance().getOne();
    }

    private synchronized long getOne() {
        LocalDateTime current = LocalDateTime.now();

        //每分钟计数清零
        if (lastSecond != current.getSecond()) {
            sequence = 0;
            lastSecond = current.getSecond();
        }

        sequence++;
        long prefix = (current.getYear() - 2000) * yearLeft +
                current.getMonthValue() * monthLeft +
                current.getDayOfMonth() * dayLeft +
                current.getHour() * hourLeft +
                current.getMinute() * minuteLeft +
                current.getSecond() * secondLeft +
                machineId * machineLeft;

        return prefix + sequence;
    }
}
